using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Logging;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using Microsoft.SemanticKernel.Plugins.OpenApi;
using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol.Transport;
using ModelContextProtocol.Protocol.Types;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using OpenAI.Chat;
using semantic_kernel_api.DataAccess;
using System.Text.Json.Serialization;
using System.Threading;
using Yitter.IdGenerator;
using static System.Runtime.InteropServices.JavaScript.JSType;

namespace semantic_kernel_api.Controllers
{
    /// <summary>
    ///  聊天
    /// </summary>
    [ApiController]
    [Route("/api/[controller]/[action]")]
    [ApiExplorerSettings(GroupName = "Chat")]
    public class ChatController : Controller
    {

        /// <summary>
        /// 发送对话消息
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task SendMessageByChatCompletion([FromBody] SendMessageDto sendMessageDto)
        {

            try
            {
                if (string.IsNullOrWhiteSpace(sendMessageDto.Query))
                {
                    return;
                }


                var modelId = sendMessageDto.modelId;  //模型名称
                var endpoint = sendMessageDto.endpoint;  //api地址
                var apiKey = sendMessageDto.apiKey;  //apikey


                //大模型初始化
                var builder = Kernel.CreateBuilder().AddOpenAIChatCompletion(modelId, new Uri(endpoint), apiKey);

                var messageid = YitIdHelper.NextId().ToString();//会话id




                //获取聊天实例
                var kernel = builder.Build();
                var chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();




                var reducer = new ChatHistoryTruncationReducer(targetCount: sendMessageDto.targetCount.Value);//添加最大历史消息限制


                var history = new ChatHistory();

                //添加系统消息 （你是一个ai助手）
                if (!string.IsNullOrWhiteSpace(sendMessageDto.prop))
                {
                    history.AddSystemMessage(sendMessageDto.prop);
                }
               

                //添加历史聊天消息
                foreach (var item in sendMessageDto.History)
                {
                    switch (item.Type)
                    {
                        case "Assistant":
                            history.AddAssistantMessage(item.content); //添加ai回复消息
                            break;
                        case "User":
                            history.AddUserMessage(item.content); //添加用户消息
                            break;
                        default:
                            break;
                    }
                    var reducedMessages = await reducer.ReduceAsync(history); //检查历史消息是否超过限制，如果超过限制则对超出部门进行摘要

                    if (reducedMessages is not null)
                    {
                        history = new ChatHistory(reducedMessages); //将摘要后的历史记录重新赋值给history
                    }
                }

                #region 添加内置插件
                //内置程序转换为插件
                kernel.Plugins.AddFromType<DefaultTool>("DefaultTool");
                //告诉ai 什么时候必须使用插件
                history.AddUserMessage("如果涉及到数字运算，你必须使用DefaultTool工具进行运算。");

                #endregion
                
                #region 动态添加内置插件  ，和上面内置插件添加方式一样，只是这里通过类名动态添加
                //var typeName = "DefaultTool";    //类名  
                //var asm = Assembly.GetExecutingAssembly(); //反射
                //Type type = asm.GetTypes().FirstOrDefault(t => t.Name == typeName); //找到这个type
                //if (type != null)
                //{
                //    KernelPlugin plugin = KernelPluginFactory.CreateFromType(type, typeName); //转换为插件
                //   kernel.Plugins.Add(plugin); //添加插件到内核
                //   history.AddUserMessage("如果涉及到数字运算，你必须使用DefaultTool工具进行运算。");
                //}

                #endregion

                #region 添加第三方接口
                foreach (var item in sendMessageDto.apilist)
                {

                    if (!string.IsNullOrWhiteSpace(item.Uri))   //通过swagger.json地址 将接口转换为插件
                    {
                        KernelPlugin plugin = await OpenApiKernelPluginFactory.CreateFromOpenApiAsync(pluginName: item.Name, new Uri(item.Uri));

                        kernel.Plugins.Add(plugin);
                    }
                    else    //通过swagger.json文件路径 将接口转换为插件
                    {

                        KernelPlugin plugin = await OpenApiKernelPluginFactory.CreateFromOpenApiAsync(pluginName: item.Name, filePath: item.Path);

                        kernel.Plugins.Add(plugin);

                    }

                }
                #endregion




                #region 添加MCP插件 
                IMcpClient client = null;
                foreach (var item in sendMessageDto.mcpServers)
                {
                    var McpserverName = item.Key.Replace("-","_"); //服务名
     
                    //MCP基础配置
                    var defaultOptions = new McpClientOptions
                    {
                        ClientInfo = new() { Name = item.Key + "McpClient", Version = "1.0.0" }
                    };

                    if (!string.IsNullOrWhiteSpace(item.Value.command)) //Stdio
                    {
                        var stdidConfig = new StdioClientTransportOptions
                        {
                            Command = item.Value.command,
                            Name = item.Key,
                            Arguments = item.Value.args,
                            EnvironmentVariables = item.Value.env,
                            WorkingDirectory = item.Value.WorkingDirectory,
                        };


                        client = await McpClientFactory.CreateAsync(
                        new StdioClientTransport(stdidConfig),
                        defaultOptions);


                        //mcp工具列表
                        var tools = await client.ListToolsAsync();
                        var functions = new List<KernelFunction>();
                        foreach (var tool in tools)
                        {
                            functions.Add(tool.ToKernelFunction(client));
                        }

                        kernel.Plugins.AddFromFunctions(McpserverName, functions);
                        //添加mcp工具
#pragma warning disable SKEXP0001
                      //  kernel.Plugins.AddFromFunctions(McpserverName, tools.Select(aiFunction => aiFunction.AsKernelFunction()));
#pragma warning restore SKEXP0001
                    }
                    else if (!string.IsNullOrWhiteSpace(item.Value.url))
                    {

                        #region 配置SSE客户端
                        var SseConfig = new SseClientTransportOptions
                        {
                            Endpoint = new Uri(item.Value.url),
                            Name = McpserverName,
                        };

                    
                  
                         client = await McpClientFactory.CreateAsync(
                         new SseClientTransport(SseConfig),
                         defaultOptions);
                        #endregion


                 
                        var tools = await client.ListToolsAsync();

                        #region 代理操作 过程可控
                        var functions = new List<KernelFunction>();
                        foreach (var tool in tools)
                        {
                            functions.Add(tool.ToKernelFunction(client));
                        }

                        kernel.Plugins.AddFromFunctions(McpserverName, functions);
                        #endregion

#pragma warning disable SKEXP0001
                        //使用自带转换方法将mcp工具转换为插件
                        //  kernel.Plugins.AddFromFunctions(McpserverName, tools.Select(aiFunction => aiFunction.AsKernelFunction()));
#pragma warning restore SKEXP0001
                    }
                    else { 
                    
                    
                    
                    }










                }








                #endregion

                #region 知识库检索
                if (!string.IsNullOrWhiteSpace(sendMessageDto.dbid))
                {
                    //知识库检索相关数据
                    var zsknr = VectorTool.selectVector(sendMessageDto.dbid, sendMessageDto.Query, 1);
                    if (zsknr.issuccess)
                    {
                        foreach (var item in zsknr.data)
                        {
                            history.AddUserMessage(item.title + "相关数据：" + item.content); //添加知识库数据
                        }

                    }
                }
                #endregion


                #region 强制要求

                // 用户强提示词，只要和系统提示词不冲突，ai不会选择忽略（写在系统提示词可能会忽略），例：让ai必须使用echarts模版展示数据
                history.AddUserMessage("如果涉及到统计信息，请使用我的提供的echarts模版展示并总结数据,我已支持echarts环境，请不要询问我是否支持。模版：```echarts\n{optionjson}\n```");

                #endregion




                history.AddUserMessage(sendMessageDto.Query); //添加提问信息



 
                //设置响应头为sse
                var Response = AppHttpContext.Current.Response;
                Response.Headers.Add("Content-Type", "text/event-stream");
                Response.Headers.Add("Cache-Control", "no-cache");
                Response.Headers.Add("Connection", "keep-alive");


                OpenAIPromptExecutionSettings openAIPromptExecutionSettings = new()
                {
                   
                    ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions,
                   // Temperature = 0,
#pragma warning disable SKEXP0001
                   // FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(options: new() { RetainArgumentTypes = true }) //解决mcp插件参数类型不匹配问题
                };

                string text = "";
                await foreach (var message in chatCompletionService?.GetStreamingChatMessageContentsAsync(history,
                               openAIPromptExecutionSettings, kernel))

                {

                    text += message.Content; //获取回复内容

                    ResponseMsg res = new ResponseMsg();
                    res.messageid = messageid;
                    res.Query = sendMessageDto.Query;
                    res.Content = text;


                    var alltoolContents = history
                      .SelectMany(container => container.Items) // 将所有的Items展平成一个序列
                      .Where(item => item.InnerContent is ChatToolCall).Select(t => t.InnerContent as ChatToolCall) // 筛选出类型为ChatToolCall的对象
                      .ToList();

                    var allFunctionResultContents = history.Where(t => t.Role == AuthorRole.Tool)
                     .SelectMany(container => container.Items) // 将所有的Items展平成一个序列
                     .Where(item => item is Microsoft.SemanticKernel.FunctionResultContent) // 筛选出类型为FunctionResultContent的对象
                     .Cast<Microsoft.SemanticKernel.FunctionResultContent>()
                     .ToList();

                    List<toolsInfo> toolsinfos=new List<toolsInfo>();

                    foreach (var toolitem in alltoolContents)
                    {
                        var function = toolitem.FunctionName;
                        var args = toolitem.FunctionArguments.ToString();
                        var id = toolitem.Id;
                        var ret = allFunctionResultContents.Where(t => t.CallId == id).FirstOrDefault()?.Result;
                        toolsinfos.Add(new toolsInfo { Name=function, Arguments=args, Return= JsonConvert.SerializeObject(ret),id=id });
                    }

                    res.Tools = toolsinfos;


                    if (message.InnerContent is OpenAI.Chat.StreamingChatCompletionUpdate chatCompletion) //获取最终token消耗情况
                    {
                        ChatTokenUsage usage = chatCompletion.Usage;
                        if (usage != null)
                        {
                            res.Usage = usage;
                        }
                    }

                    string dataString = "data:" + JsonConvert.SerializeObject(res)  + "\n\n";
                    await Response.WriteAsync(dataString);
                    await Response.Body.FlushAsync();

                }


            }
            catch (Exception ex)  //异常将返回状态204
            {
                // throw;
            }
        }

        private Type ConvertParameterDataType(JsonSchemaProperty property, bool required)
        {
            var type = property.Type switch
            {
                "string" => typeof(string),
                "integer" => typeof(int),
                "number" => typeof(double),
                "boolean" => typeof(bool),
                "array" => typeof(List<string>),
                "object" => typeof(Dictionary<string, object>),
                _ => typeof(object)
            };

            return !required && type.IsValueType ? typeof(Nullable<>).MakeGenericType(type) : type;
        }

    }



}


